/*
 * vector.h
 *
 *  Created on: 28.06.2011
 *      Author: marcell
 */

#ifndef __VECTOR_H__
#define __VECTOR_H__

#include <export.h>
#include <math.h>

/**
 * \addtogroup math
 * @{
 */

/**
 * \brief 2D vector
 */
struct ceVector2f
{
    float x;
    float y;
    inline ceVector2f () : x(0), y(0) { }
    inline ceVector2f (float x, float y) : x(x), y(y) { }

    inline ceVector2f operator+ (const ceVector2f& v) const
    {
      return ceVector2f (x + v.x, y + v.y);
    }

    inline ceVector2f operator- (const ceVector2f& v) const
    {
      return ceVector2f (x - v.x, y - v.y);
    }

    inline ceVector2f operator- () const
    {
      return ceVector2f (-x, -y);
    }

    inline ceVector2f& operator+= (const ceVector2f& v)
    {
      x += v.x;
      y += v.y;
      return *this;
    }

    inline ceVector2f& operator-= (const ceVector2f& v)
    {
      x -= v.x;
      y -= v.y;
      return *this;
    }

    inline ceVector2f operator* (const ceVector2f& v) const
    {
      return ceVector2f (x * v.x, y * v.y);
    }

    inline friend ceVector2f operator* (const ceVector2f& v0, float v1)
    {
      return ceVector2f (v0.x * v1, v0.y * v1);
    }

    inline friend ceVector2f operator* (float v0, const ceVector2f& v1)
    {
      return ceVector2f (v1.x * v0, v1.y * v0);
    }

    inline ceVector2f& operator*= (float v)
    {
      x *= v;
      y *= v;
      return *this;
    }

    inline friend ceVector2f operator/ (const ceVector2f& v, const float& d)
    {
      return ceVector2f (v.x / d, v.y / d);
    }

    inline ceVector2f operator/ (const ceVector2f& d) const
    {
      return ceVector2f (x / d.x, y / d.y);
    }

    inline ceVector2f& operator/= (float d)
    {
      x /= d;
      y /= d;
      return *this;
    }

    inline float Length () const
    {
      return sqrt (x*x + y*y);
    }

    inline float Dot () const
    {
      return x*x + y*y;
    }

    inline float Dot (const ceVector2f& v) const
    {
      return x*v.x + y*v.y;
    }

    inline ceVector2f& Normalize ()
    {
      float l = Length();
      x /= l;
      y /= l;
      return *this;
    }

    inline ceVector2f Normalized ()  const
    {
      float l = Length();
      return ceVector2f (x / l, y / l);
    }

    inline float Angle (const ceVector2f& other) const
    {
      return acos(Normalized().Dot(other.Normalized()));
    }

};

/**
 * \brief 3D vector
 */
struct ceVector3f
{
    float x;
    float y;
    float z;

    inline ceVector3f () : x(0), y(0), z(0) {}

    inline ceVector3f (float x, float y, float z) : x(x), y(y), z(z) { }

    inline ceVector3f operator+ (const ceVector3f& v) const
    {
      return ceVector3f (x + v.x, y + v.y, z + v.z);
    }

    inline ceVector3f operator- (const ceVector3f& v) const
    {
      return ceVector3f (x - v.x, y - v.y, z - v.z);
    }

    inline ceVector3f operator- () const
		{
      return ceVector3f (-x, -y, -z);
		}

    inline ceVector3f& operator+= (const ceVector3f& v)
    {
      x += v.x;
      y += v.y;
      z += v.z;
      return *this;
    }

    inline ceVector3f& operator-= (const ceVector3f& v)
    {
      x -= v.x;
      y -= v.y;
      z -= v.z;
      return *this;
    }

    inline ceVector3f operator* (const ceVector3f& v) const
    {
      return ceVector3f (x * v.x, y * v.y, z * v.z);
    }

    inline friend ceVector3f operator* (const ceVector3f& v0, float v1)
    {
      return ceVector3f (v0.x * v1, v0.y * v1, v0.z * v1);
    }

    inline friend ceVector3f operator* (float v0, const ceVector3f& v1)
    {
      return ceVector3f (v1.x * v0, v1.y * v0, v1.z * v0);
    }

    inline ceVector3f& operator*= (float v)
    {
      x *= v;
      y *= v;
      z *= v;
      return *this;
    }

    inline friend ceVector3f operator/ (const ceVector3f& v, const float& d)
    {
      return ceVector3f (v.x / d, v.y / d, v.z / d);
    }
    
    inline ceVector3f operator/ (const ceVector3f& d) const
    {
      return ceVector3f (x / d.x, y / d.y, z / d.z);
    }

    inline ceVector3f& operator/= (float d)
    {
      x /= d;
      y /= d;
      z /= d;
      return *this;
    }

    inline float Length () const
    {
      return sqrt (x*x + y*y + z*z);
    }

    inline float Dot () const
    {
      return x*x + y*y + z*z;
    }

    inline float Dot (const ceVector3f& v) const
    {
      return x*v.x + y*v.y + z*v.z;
    }

    inline ceVector3f& Normalize ()
    {
      float l = Length();
      x /= l;
      y /= l;
      z /= l;
      return *this;
    }

    inline ceVector3f Normalized ()  const
    {
      float l = Length();
      return ceVector3f (x / l, y / l, z / l);
    }

    inline ceVector3f operator% (const ceVector3f& v) const
    {
      return ceVector3f (y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
    }

    inline float Angle (const ceVector3f& other) const
    {
      return acos(Normalized().Dot(other.Normalized()));
    }

    inline float Min() const
    {
      return x < y && x < z ? x : y < x && y < z ? y : z;
    }
};


/**
 * \brief 4D vector
 */
struct ceVector4f
{
    float x;
    float y;
    float z;
    float w;
    inline ceVector4f (float x = 0.0f, float y = 0.0f, float z = 0.0f, float w = 1.0f) : x(x), y(y), z(z), w(w) { }
    inline ceVector4f (const ceVector3f& v, float w = 1.0f) : x(v.x), y(v.y), z(v.z), w(w) { }

		const ceVector3f& AsVector3 () const
    {
			return reinterpret_cast<const ceVector3f&>(*this);
    }
		ceVector3f& AsVector3 ()
		{
			return reinterpret_cast<ceVector3f&>(*this);
		}
};


/** @} */

#endif /* ! __VECTOR_H__ */
